package core.impl;

import config.Bean;
import config.Property;
import config.XmlConfig;
import core.BeanFactory;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import utils.BeanUtil;

public class ClassPathXmlApplicationContext implements BeanFactory{
    //定义一个IOC容器，其实就是一个Map
    private Map<String,Object> ioc;

    private Map<String, Bean> config;

    /**
     * 构造函数
     * 1.初始化IOC容器
     * 2.加载配置文件， 生成bean对象向放入IOC容器
     */
    public ClassPathXmlApplicationContext(String path){
        //初始化IOC容器
        ioc = new HashMap<String,Object>();
        //读取配置文件
        config = XmlConfig.getConfig(path);
        if(config != null){
            for(Entry<String,Bean> entry:config.entrySet()){
                String beanId = entry.getKey();
                Bean bean = entry.getValue();

                //根据bean生成相应的对象
                Object object = createBean(bean);
            }
        }
    }

    /**
     * 根据bean生成对象实例
     * @param bean
     * @return
     */
    private Object createBean (Bean bean){
        String beanId = bean.getId();
        String className = bean.getClassName();

        Class c = null;
        Object object = null;

        //根据bean的class属性生成对象
        try {
            c = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("您配置的class属性不合法:"+className);
        }

        try {
            object  = c.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("该类缺少一个无参构造方法:"+className);
        }

        //将bean的属性封装到对象中
        if(bean.getProperties() != null){
            for(Property p:bean.getProperties()){
                //1.配置文件中使用value属性注入
                if(p.getValue() != null){
                    //获取属性对应的setter方法
                    Method getMethod = BeanUtil.getSetterMethod(object
                            ,p.getName());
                    try {
                        getMethod.invoke(object,p.getValue());
                    } catch (Exception e) {
                        throw new RuntimeException("属性名称不合法或者没有相应的getter方法："+p.getName());
                    }
                }
                //2.配置文件中使用的是ref属性注入
                if(p.getRef() != null){
                    //获取属性对应的setter方法
                    Method getMethod = BeanUtil.getSetterMethod(object,p.getName());
                    //从容器中找到依赖的对象
                    Object obj  = ioc.get(p.getRef());
                    if(obj == null){
                        throw new RuntimeException("没有找到依赖的对象："+p.getRef());
                    }else{
                        //调用set方法注入
                        try {
                            getMethod.invoke(object,obj);
                        } catch (Exception e) {
                            throw new RuntimeException("属性名称不合法或者没有相应的getter方法："+p.getName());
                        }
                    }
                }
            }
            return object;
        }
        return null;
    }

    public Object getBean(String beanName) {
        return ioc.get(beanName);
    }
}
